/*
  是不是很迷惑有两个运行整理的文件？
  其实这两个文件的功能目前是一样的，
  只不过另一个文件的代码太乱，且不易于
  扩展，所以重新写了一份
*/

let data;
try {
    data = JSON.parse(files.read("./配置.json"));
} catch (err) {
    console.error(err);
    toast("请先添加配置!");
    exit();
}

setTimeout(() => {
    let k = new stun(data);
    let p = (new Date()).getTime();
    let ri = k.start();
    
    let tos = "本次整理文件数量：" + ri +
        ('\n花费时间:' + ((new Date()).getTime() - p)) + "毫秒";
    toastLog(tos);
    //广播给其他应用
    app.sendBroadcast({
        action: "android.intent.selp.filecso",
        extras: {
            txt: tos
        }
    });
}, 0);

function stun(config) {
    //绑定events.emitter()
    events.__asEmitter__(this);
    /* 部署了3个事件,这些事件都是同步的
      start : 运行时触发，
      end : 运行结束时触发
      mobileFile : 移动文件成功时触发,有三个参数
    */
    this.config = config;
    this.data = config.data;
    this.moshi = config.moshi;
    this.scanMedia = data.ismedia; //记录是否扫描媒体
    this.Globalfilters = []; //全局过滤器
    this.ConfigFilter = [];
    let filterOve = {
        config: config,
        Globalfilters: this.Globalfilters,
        ConfigFilter: this.ConfigFilter,
        filter: function(path, name) {
            for (let i = 0; i < this.Globalfilters.length; i++) {
                let a = this.Globalfilters[i];
                if (!a(path, name, this.config)) return false;
            }
            for (let i = 0; i < this.ConfigFilter.length; i++) {
                let filter = this.ConfigFilter[i];
                if (!filter(path, name, this)) return false;
            }
            return true;
        }
    }
    config.data.forEach(v => v.__proto__ = filterOve);

    //通知媒体扫描文件,fomp原文件路径，top移动后文件路径
    this.on('mobileFile', function(fomp, top, config) {
        log("移动成功：" + fomp + ">>>>>" + top);
        if (config.scanMedia) {
            media.scanFile(fomp);
            media.scanFile(top);
        }
    })
    //添加是否扫描隐藏文件的过滤器
    this.addGlobalFilter(function(path, name, config) {
        if (!config.iofile) {
            return name[0] !== "."; //忽略.开头的文件
        }
        return true;
    });
    //添加文件大小过滤器
    this.addConfigFilter(function(path, name, config) {
        let sizeSet = config.sizeSet;
        if (!sizeSet) return true;
        let fileSize = (new java.io.File(path)).length() / 1024; //取得文件大小-kb
        if (fileSize < sizeSet.minSize) return false;
        if (sizeSet.maxSize > 0 && fileSize > sizeSet.maxSize) return false;
        return true;
    })
}
/**
 * 添加全局过滤器
 * @param p 过滤器函数，
 *    过滤器接收三个参数:
 *    path:文件的绝对路径
 *    name:文件名
 *    config:全局配置
 *    返回true表示通过
 */
stun.prototype.addGlobalFilter = function(p) {
    this.Globalfilters.push(p);
}

/**
 * 添加局部过滤器
 * 第三个的参数为局部配置，其他和上面一样
 */
stun.prototype.addConfigFilter = function(p) {
    this.ConfigFilter.push(p);
}
stun.prototype.start = function() {
    this.emit('start');
    let fileArr = [];
    this.scanning(this.data, fileArr);
    let a = this.moveFiles(fileArr);
    this.emit('end', a);
    return a;
}
//扫描文件
stun.prototype.scanning = function(configArr, fileArr) {
    configArr.forEach((config) => {
        if (!files.isDir(config.dir)) return; //指定文件夹不存在则跳过
        let childDir = []; //记录子目录
        files.listDir(config.dir).forEach((fileName) => {
            let path = files.join(config.dir, fileName); //组合绝对路径
            if (files.isDir(path)) {
                let dir = Object.create(config);
                dir.dir = path;
                dir.sdt--;
                childDir.push(dir);
                return false;
            }
            //过滤器判断返回false则跳过
            if (!config.filter(path, fileName)) return false;
            let fileInfo = Object.create(config);
            fileInfo.filePath = path;
            fileInfo.fileName = fileName;
            fileArr.push(fileInfo);
            return true;
        });
        if (config.sdt > 0) return this.scanning(childDir, fileArr);
    })
}
//进行文件移动
stun.prototype.moveFiles = function(fileArr) {
    let ri = 0; //记录移动文件成功的数量
    fileArr.forEach((fileInfo) => {
        let fomp = fileInfo.filePath; //要移动的文件绝对路径
        let moshi = this.moshi.concat(fileInfo.moshi || []); //合并全局规则与独立规则
        for (let i = moshi.length - 1; i >= 0; i--) {
            let tofile = moshi[i].tofile; //目标文件夹
            let name = moshi[i].name; //文件类型集
            if (!files.isDir(tofile)) {
                toastLog(tofile + "文件夹不存在");
                return;
            }
            let top = files.join(tofile, fileInfo.fileName); //目标路径
            for (let i2 = 0; i2 < name.length; i2++) {
                if (fileInfo.fileName.toLowerCase().endsWith("." + name[i2].toLowerCase())) {
                    //如果文件已存在
                    if (files.exists(top)) {
                        console.warn("文件重复：" + top);
                        return;
                    }
                    if (!files.move(fomp, top)) {
                        console.warn("移动文件失败：" + fomp + ">>>>>" + top);
                    } else {
                        this.emit('mobileFile', fomp, top, this);
                        ri += 1;
                    }
                    return;
                }
            }
        }
    });
    return ri;
}